/*
 * Teilt das Spielfeld in Bereiche und erkennt Topologien.
 */

package de.hsb.ai.agent.misterx.brain.geoanalyser;

import game.Move;
import i18n.I18n;
import jade.core.AID;

import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;

import javax.swing.JOptionPane;

import de.hsb.ai.agent.misterx.brain.Brain;


public class GeoAnalyser implements IGeoAnalyser {

	//DATA
	public List<Polygon> _polygons = new ArrayList<Polygon>(); //Konvexe Hülle
	public List<Rectangle> _rectangles = new ArrayList<Rectangle>(); //Fläche in Prozent
	public List<Point2D> _points = new ArrayList<Point2D>(); //Schwerpunkte
	public List<Integer> _numbers = new ArrayList<Integer>(); //Fläche in Prozent
	public List<Point2D> _orientation = new ArrayList<Point2D>(); //Fläche in Prozent

	private HashMap<AID, int[]> _currentQuadrant = new HashMap<AID,  int[]>();
	private HashMap<AID, Boolean> _currentInVision = new HashMap<AID,  Boolean>();
	private boolean _insideConvexHull = false;
	
	private Point[] _nodePositions;
	private Point _minPosition;
	private Point _maxPosition;
	
	private int _noOfNodes;
	private double _polygonOrientation;
	private double _polygonExzentrität;
	

	public GeoAnalyser() {
		this.readPosFile();
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
//  TXT-READER NODE KOODINATEN                             
//////////////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Liesst die Koordinaten der Nodes aus dem File.
	 */
	private void readPosFile() {
		String resource = "SCOTPOS.TXT";
		URL url = getClass().getClassLoader().getResource(resource);
		try {
			InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(resource);
			InputStreamReader inputStreamReader = new InputStreamReader(resourceAsStream);
			BufferedReader map = new BufferedReader(inputStreamReader);
			String buffer = map.readLine();
			StringTokenizer token = new StringTokenizer(buffer);
			this._noOfNodes = Integer.parseInt(token.nextToken());
			this._nodePositions = new Point[this._noOfNodes];

			for (int i = 0; i < this._noOfNodes; i++) {
				buffer = map.readLine();
				token = new StringTokenizer(buffer);
				int node = Integer.parseInt(token.nextToken());
				int x = Integer.parseInt(token.nextToken());
				int y = Integer.parseInt(token.nextToken());

				if(i == 0) {
					this._minPosition = new Point(x, y);
					this._maxPosition = new Point(x, y);
				}
				
				if(x < this._minPosition.x) this._minPosition.x = x;
				if(y < this._minPosition.y) this._minPosition.y = y;
				
				if(x > this._maxPosition.x) this._maxPosition.x = x;
				if(y > this._maxPosition.y) this._maxPosition.y = y;

				_nodePositions[node] = new Point(x, y);
			}
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, "GeoAnalyzer: " + I18n.tr("ErrorFileNotFound", url), I18n.tr("ErrorTitle"), JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
//  FUNKTIONEN                            
//////////////////////////////////////////////////////////////////////////////////////////////////
		

	/**
	 * gibt den Index zurück in welchem Quadranten sich die angegebene Node befindet. (Rasterung des Boards)
	 * @param position
	 * @param divideX
	 * @param divideY
	 * @return
	 */
	public int[] getQuadrant(int nodeIndex, int divideX, int divideY) {
		Point position = this.getNodePosition(nodeIndex);
		return getQuadrant(position, divideX, divideY);
	}
	
	/**
	 * gibt den Index zurück in welchem Quadranten sich die angegebene Position befindet. (Rasterung des Boards)
	 * @param position
	 * @param divideX
	 * @param divideY
	 * @return
	 */
	public int[] getQuadrant(Point2D position, int divideX, int divideY) {
		int[] index = new int[2];
		
		if(position == null) return index;

		Rectangle rectangle = this.getBoardSize();
		int j = (int) (position.getX() / (rectangle.width / divideX));
		int i = (int) (position.getY() / (rectangle.height / divideY));
		
		index[0] = i;
		index[1] = j;
		
		return index;
	}
	
//////////////////////////////////////////////////////////////////////////////////////////////////
// 										FUNKTIONS                                                     
//////////////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * gibt die Node Koordinaten (euklidisch) eines Nodes zurück.
	 * @param index
	 * @return
	 */
	public Point getNodePosition(int index) {
		if(index >= 0 && index < _nodePositions.length) {
			return _nodePositions[index];
		}
		return null;
	}
	
	/**
	 * gibt den DiffeneceVektor zwischen zwei Nodes zurück.
	 * @param nodeIndexFrom
	 * @param nodeIndexTo
	 * @return
	 */
	public Point2D getDifferenceVector(int nodeIndexFrom, int nodeIndexTo) {
		Point2D distanceVector = null;
		
		Point nodePositionFrom = this.getNodePosition(nodeIndexFrom);
		Point nodePositionTo = this.getNodePosition(nodeIndexTo);
		if(nodePositionFrom != null && nodePositionTo != null) {
			distanceVector = new Point2D.Float(nodePositionTo.x - nodePositionFrom.x, nodePositionTo.y - nodePositionFrom.y);
		}
		
		return distanceVector;
	}
	
	/**
	 * gibt die Größe des Spielbretts zurück.
	 * @return
	 */
	private Rectangle getBoardSize() {
		return new Rectangle(this._minPosition.x, this._minPosition.y, this._maxPosition.x - this._minPosition.x, this._maxPosition.y - this._minPosition.y);
	}
	
	/**
	 * Normalisiert einen Vektor.
	 */
	@SuppressWarnings("unused")
	private Point2D normalizeVector(Point2D direction) {
		float vectorLength = (float) Math.sqrt((direction.getX() * direction.getX()) + (direction.getY() * direction.getY()));
		return new Point2D.Float((float)(1/vectorLength * direction.getX()), (float)(1/vectorLength * direction.getY()));
	}
	
	/**
	* gibt die Distanz zwischen zwei NodeIndexen.
	*/
	public float getDistance(int nodeIndex1, int nodeIndex2) {
		Point nodePosition1 = this.getNodePosition(nodeIndex1);
		Point nodePosition2 = this.getNodePosition(nodeIndex2);
		
		float distX = nodePosition2.x - nodePosition1.x;
		float distY = nodePosition2.y - nodePosition1.y;
		return (float) Math.sqrt(distX*distX + distY*distY);
	}
	
	/**
	 * gibt die Distanz zwischen zwei Spielern.
	 * @param nodeIndex1
	 * @param nodeIndex2
	 * @return
	 */
	public float getDistance(AID aid1, AID aid2) {
		Move move1 = Brain.HISTORYCAPTURER.getLastPlayerMove(aid1);
		Move move2 = Brain.HISTORYCAPTURER.getLastPlayerMove(aid2);
		
		if(move1 != null && move2 != null) {
			return getDistance(move1.getNode(), move2.getNode());
		}
		
		return -1;
	}

	/**
	* prüft ob ein DisplayObject im Sichtfeld ist.
	*/
	public boolean isInVision(AID enemy, int nodeIndex, boolean enableAngle, int angle) { //checkt ob ein MovieClip im Sichtfeld eines anderen MovieClips steht
		Move lastPlayerMove = Brain.HISTORYCAPTURER.getLastPlayerMove(enemy);
		int enemyNodeIndex = lastPlayerMove.getNode();
		
		Point2D enemyMovingDirection = Brain.HISTORYCAPTURER.getHistory(enemy).getLastMovingDirection();
		if(enemyMovingDirection != null) {
			//Distance zwischen dem NodeIndex wo der Feind steht und wo man selbst steht.
			Point2D distanceVector = this.getDifferenceVector(nodeIndex, enemyNodeIndex);
			//Berechne das Skalarprodukt derer.
			float scalarProduct = (float) (distanceVector.getX() * enemyMovingDirection.getX() + distanceVector.getY() * enemyMovingDirection.getY()); //wenn positiv vorne , wenn negativ hinter Zombie
			
			//Mit zusätzlichem Winkel in dem sich das Objekt befinden kann.
			if(enableAngle) {
				float distanceVectorLength = (float) Math.sqrt((distanceVector.getX() * distanceVector.getX()) + (distanceVector.getY() * distanceVector.getY()));
				float steigungLength = (float) Math.sqrt((enemyMovingDirection.getX() * enemyMovingDirection.getX()) + (enemyMovingDirection.getY() * enemyMovingDirection.getY()));
				
				float calc_angle = (float) Math.acos(scalarProduct / (distanceVectorLength * steigungLength));
				calc_angle = (float) (calc_angle * 360/2/Math.PI);//(float) (calc_angle / (Math.PI * 180));
				
				int limitedVisionField = 180 - (angle /2); 
			
				if(calc_angle > limitedVisionField) {
					return true;
				} else {
					return false;
				}
				
			} else {
				if(scalarProduct > 0) {
					return false;
				} else {
					return true;
				}
			}
		}
		return false;
		
	}
	
	/**
	 * prüft ob sich eine Spieler in einer bestimmten Reichweite eines Nodes befindet.
	 * @param enemy
	 * @param nodeIndex
	 * @param range
	 * @return
	 */
	public boolean isInRange(AID enemy, int nodeIndex, float range) {
		Move lastMove = Brain.HISTORYCAPTURER.getHistory(enemy).getLastMove();
		if(lastMove != null) {
			float distance = this.getDistance(lastMove.getNode(), nodeIndex);
			if(distance <= range) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * gibt ein geometrisches Rechteck zurück was alle Dektive einschliesst. (Box)
	 * @return
	 */
	private Rectangle getDangerRectangle() {
		List<AID> enemys = Brain.getEnemyAIDs();
		if(enemys.size() < 3) return null;
		
		Rectangle rectangle = null;
		
		Point minPosition = null;
		Point maxPosition = null;
		
		for(int i = 0; i < enemys.size(); i++) {
			Move lastMove = Brain.HISTORYCAPTURER.getLastPlayerMove(enemys.get(i));
			if(lastMove != null) {
				Point currentPosition = this.getNodePosition(lastMove.getNode());
				if(i == 0) {
					minPosition = new Point(currentPosition.x, currentPosition.y);
					maxPosition = new Point(currentPosition.x, currentPosition.y);
				}
				
				if(currentPosition.x < minPosition.x) minPosition.x = currentPosition.x;
				if(currentPosition.y < minPosition.y) minPosition.y = currentPosition.y;
				
				if(currentPosition.x > maxPosition.x) maxPosition.x = currentPosition.x;
				if(currentPosition.y > maxPosition.y) maxPosition.y = currentPosition.y;
			}
			
		}
		
		if(minPosition != null) {
			rectangle = new Rectangle(minPosition.x, minPosition.y, maxPosition.x - minPosition.x, maxPosition.y - minPosition.y);
		}
		return rectangle;
	}
	
	/**
	 * prüft ob sich ein Node innerhalb eins Rectangles befindet.
	 * @param nodeIndex
	 * @param rectangle
	 * @return
	 */
	@SuppressWarnings("unused")
	private boolean isInRectangle(int nodeIndex, Rectangle rectangle) {
		Point nodePosition = this.getNodePosition(nodeIndex);
		
		//rectangle.contains(nodePosition);
		if(nodePosition.x >= rectangle.getMinX() && nodePosition.x <= rectangle.getMaxX() 
				&& nodePosition.y >= rectangle.getMinY() && nodePosition.y <= rectangle.getMaxY()) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * gibt ein das kleinste umschlissende Polygon zurück was alle Dektive einschliesst. (Konvexe-Hülle)/GrahamScan
	 * @return
	 */
	private Polygon getDangerConvexHull() {
		List<AID> enemys = Brain.getEnemyAIDs();
		if(enemys.size() < 3) return null;
		
		CHPoint[] enemiePostition = new CHPoint[enemys.size()];
		
		//Umsetzen auf JarvisMarch/ConvexHull Struktur.
		for(int i = 0; i < enemys.size(); i++) {
			Move lastMove = Brain.HISTORYCAPTURER.getLastPlayerMove(enemys.get(i));
			if(lastMove != null) {
				Point nodePosition = this.getNodePosition(lastMove.getNode());
				CHPoint p = new CHPoint(nodePosition.x, nodePosition.y);
				enemiePostition[i] = p;
			}
		}
		
		//Konvexe Hülle erstellen.
		ConvexHull convexHull = new ConvexHull();
		int h = convexHull.computeHull(enemiePostition);
	    
		//Umsetzen auf Polygonstruktur.
		int[] xPoints = new int[h]; 
		int[] yPoints = new int[h];

		for(int i = 0; i < h; i++) {
			xPoints[i] = (int) enemiePostition[i].x;
			yPoints[i] = (int) enemiePostition[i].y;
		}
		
		return new Polygon(xPoints, yPoints, h);
	}
	
	/**
	 * überprüft ob sich eine NodeIndex innerhalb eines Polygons befindet.
	 * @param nodeIndex
	 * @param polygon
	 * @return
	 */
	public boolean isInPolygon(int nodeIndex, Polygon polygon) {
		Point nodePosition = this.getNodePosition(nodeIndex);
		return polygon.contains(nodePosition);
	}
	
	/**
	 * Einholen des neusten Wissen über die Welt.
	 */
	@Override
	public void update() {
		this.execute();
	}
	
	/**
	 * berechnet die Fläche eines Polygons. 
	 * A = 1/2 (Sum<N-1, i=0> (xi yi+1 - xi+1 yi))
	 * @param polygon
	 * @return
	 */
	private float calculateArea(Polygon polygon) {
		float area = 0.0f;
		
		if(polygon == null) return -1;
		
		int n = polygon.xpoints.length;
		for(int i = 0; i < n; i++)  {
			if(i == n-1) { //verbindet letzen mit ersten Punkt.
				area += (polygon.xpoints[i] * polygon.ypoints[0])-(polygon.xpoints[0] * polygon.ypoints[i]);
			}  else  {
				area += (polygon.xpoints[i] * polygon.ypoints[i+1])-(polygon.ypoints[i] * polygon.xpoints[i+1]);
			}
		}
			
		area /= 2;
		if(area < 0) area *= -1;
		
		return area;
	}
	
	/**
	 * gibt den Prozentuallen Nutzen eines Polygons zur gesamtFläche(Spielbrett) zurück.
	 * @param polygon
	 * @return
	 */
	private float calculateAreaRatio(Polygon polygon) {
		double polygonArea = Brain.GEOANALYSER.calculateArea(polygon);
		Rectangle boardRectangle = Brain.GEOANALYSER.getBoardSize();
		return (float) (1.0f/(boardRectangle.height * boardRectangle.width) * polygonArea);
	}
	
	/**
	 * Berechnet den Schwerpunkt eines Polygons. 
	 * cx = 1/6A (Sum<N-1, i=0> (xi + xi+1)(xi yi+1 - xi+1 yi))
	 * cy = 1/6A (Sum<N-1, i=0> (yi + yi+1)(yi yi+1 - xi+1 yi))
	 * @param size
	 * @param xSum
	 * @param ySum
	 * @return
	 */
	private Point2D calculateCentroid(Polygon polygon) {
		float cx = 0.0f; 
		float cy = 0.0f;
		
		if(polygon == null) return null;
		
		int n = polygon.xpoints.length;
        for (int i = 0; i < n; i++) {
        	if(i == n-1) { //verbindet letzen mit ersten Punkt.
        		 cx = cx + (polygon.xpoints[i] + polygon.xpoints[0]) * (polygon.ypoints[i] * polygon.xpoints[0] - polygon.xpoints[i] * polygon.ypoints[0]);
                 cy = cy + (polygon.ypoints[i] + polygon.ypoints[0]) * (polygon.ypoints[i] * polygon.xpoints[0] - polygon.xpoints[i] * polygon.ypoints[0]);
        	} else {
        		 cx = cx + (polygon.xpoints[i] + polygon.xpoints[i+1]) * (polygon.ypoints[i] * polygon.xpoints[i+1] - polygon.xpoints[i] * polygon.ypoints[i+1]);
                 cy = cy + (polygon.ypoints[i] + polygon.ypoints[i+1]) * (polygon.ypoints[i] * polygon.xpoints[i+1] - polygon.xpoints[i] * polygon.ypoints[i+1]);
        	}
        }
        
        float area = this.calculateArea(polygon);
        cx /= (6.0f * area);
        cy /= (6.0f * area);
        
        return new Point2D.Float(Math.abs(cx), Math.abs(cy));
    }
	
	/**
	 * Ermittle Zentrale Momente.
	 */
	private int[] calculteCentralMoments(Polygon polygon, Point2D centroid) {
		if(polygon == null) return null;
		
		int n = polygon.xpoints.length;
		int[] centralMoments = new int[3];
		
		int centralMoment_1_1 = 0; //0
		int centralMoment_2_0 = 0; //1
		int centralMoment_0_2 = 0; //2
		
		for (int i = 0; i < n; i++) {
			centralMoment_1_1 += Math.pow((polygon.xpoints[i] - centroid.getX()), 1) * Math.pow((polygon.ypoints[i] - centroid.getY()), 1);
			centralMoment_2_0 += Math.pow((polygon.xpoints[i] - centroid.getX()), 2) * Math.pow((polygon.ypoints[i] - centroid.getY()), 0);
			centralMoment_0_2 += Math.pow((polygon.xpoints[i] - centroid.getX()), 0) * Math.pow((polygon.ypoints[i] - centroid.getY()), 2);
		}
		
		centralMoments[0] = centralMoment_1_1;
		centralMoments[1] = centralMoment_2_0;
		centralMoments[2] = centralMoment_0_2;
		
		return centralMoments;
	}
	
	/**
	 * Ermittle Orientierungen.
	 * @param centralMoments
	 * @return
	 */
	private double calculateOrientation(int[] centralMoments) {
    	return 0.5d*(Math.atan2((2*centralMoments[0]), (centralMoments[1] - centralMoments[2])));
    }
	
	/**
	 * Ermittelt die Exzentrizität.(Wert/Mass für die Rundheit) - Wieviel von einem Kreis abgewichen wird.
	 * @param centralMoment_1_1
	 * @param centralMoment_2_0
	 * @param centralMoment_0_2
	 * @return
	 */
	private double calculateExzentrizität(int[] centralMoments) {
    	double a = Math.sqrt(Math.pow((centralMoments[1] - centralMoments[2]), 2) + (4 * Math.pow(centralMoments[0], 2))); 
    	double length = (centralMoments[1] + centralMoments[2] + a) / (centralMoments[1] + centralMoments[2] - a);
    	return length;
    }
	
    /**
     * Ermittelt den Radius der Elipse in Orientierungsrichtung.
     */
	private double calculateEllipseRadius(int[] centralMoments) {
    	double a = centralMoments[1] + centralMoments[2] + Math.sqrt(Math.pow((centralMoments[1] - centralMoments[2]), 2) + (4 * Math.pow(centralMoments[0], 2))); 
		return Math.sqrt(2*a/20000);
    }
    
    /**
     * Ermittelt den Mittelpunkt zwischen zwei Punkten.
     * @param a
     * @param b
     * @return
     */
    public Point2D calculateLineCenter(Point a, Point b) {
    	Point2D differenceVector = new Point2D.Float((float)(b.getX() - a.getX()), (float)(b.getY() - a.getY()));

    	float length = (float) Math.sqrt(differenceVector.getX() * differenceVector.getX() + differenceVector.getY() * differenceVector.getY());
    	
    	return new Point2D.Float((float)(a.getX() + (1/length * differenceVector.getX()) * length/2), (float)(a.getY() + (1/length * differenceVector.getY()) * length/2)); //oder gleich x/length, y/length
    }
    
    /**
     * weisst allen Spielern einen Quadranten zu.
     */
    private void captureQuadrant() {
    	List<AID> player = Brain.getAllAIDs();
		for(AID aid : player) {
			Move move = Brain.HISTORYCAPTURER.getLastPlayerMove(aid);
			int[] qudrant = Brain.GEOANALYSER.getQuadrant(move.getNode(), 2, 2);
			this._currentQuadrant.put(aid, qudrant);
		}
    }
    
    /**
     * weisst allen Spieler eine Variable zu ob sie Mr.X sehen.
     */
    private void captureVision() {
    	Move lastMove = Brain.HISTORYCAPTURER.getLastPlayerMove(Brain.getOwnAID());
		if(lastMove != null) {
			int nodeIndex = lastMove.getNode();
			List<AID> enemys = Brain.getEnemyAIDs();
			for(AID aid : enemys) {
				boolean isInVision = Brain.GEOANALYSER.isInVision(aid, nodeIndex, true, 90);
				this._currentInVision.put(aid, isInVision);
			}
		}	
    }
    
    /**
     * führt alle Berechnungen zur konvexen Hülle aus. (konvexe Hulle, Schwerpunkt, Orientierung, Exzentrität)
     */
    private void captureConvexHullStuff() {
    	this._rectangles.add(this.getDangerRectangle());
    	this._polygons.add(this.getDangerConvexHull());
		this._numbers.add((int) (100* this.calculateAreaRatio(this._polygons.get(this._polygons.size()-1))));
		this._points.add(this.calculateCentroid(this._polygons.get(this._polygons.size()-1)));
		
		int[] centralMoments =  this.calculteCentralMoments(this._polygons.get(this._polygons.size()-1), this._points.get(this._points.size()-1));
		if(centralMoments != null) {
			this._polygonOrientation = this.calculateOrientation(centralMoments);
			this._polygonExzentrität = this.calculateExzentrizität(centralMoments);
			double factor = this.calculateEllipseRadius(centralMoments);
			
			int orientationX = (int)(factor * Math.cos(this._polygonOrientation) * 1 * this._polygonExzentrität);
			int orientationY = (int)(factor * Math.sin(this._polygonOrientation) * 1 * this._polygonExzentrität);
			this._orientation.add(new Point(orientationX, orientationY));
		}
		
		Move move = Brain.HISTORYCAPTURER.getLastPlayerMove(Brain.getOwnAID());
		if(move != null) {
			this._insideConvexHull = this.isInPolygon(move.getNode(), this._polygons.get(this._polygons.size()-1));
		}

    }
    
    /**
     * gibt die letze bekannte konvexe Hülle zurück.
     * @return
     */
    public Polygon getCurrentConvexHull() {
    	return this._polygons.get(this._polygons.size()-1);
    }
    
    /**
     * gibt die letze bekannte umschliessende Rechteck zurück.
     * @return
     */
    public Rectangle getCurrentRectangleHull() {
    	return this._rectangles.get(this._rectangles.size()-1);
    }
    
    /**
     * gibt den letzen bekannten Schwerpunkt der konvexen Hülle zurück.
     * @return
     */
    public Point2D getCurrentConvexHullCentroid() {
    	return this._points.get(this._points.size()-1);
    }
    
    /**
     * gibt die letze bekannte gesamtfläche der konvexen Hülle in Prozent zurück (Vehältnis zur Gesamtfläche des Spielbrettes).
     * @return
     */
    public int getCurrentConvexHullArea() {
    	if(this._numbers != null && this._numbers.size() >= 1) {
    		return this._numbers.get(this._numbers.size()-1);
    	}
    	return -1;
    	
    }
    
    /**
     * gibt die letze bekannten Richtungsvektor der konvexen Hülle zurück.
     * @return
     */
    public Point2D getCurrentConvexHullDirection() {
    	return this._orientation.get(this._orientation.size()-1);
    }
    
    /**
     * gibt den letzen Quadranten in dem sich eine Spieler aufhält zurück.
     * @param aid
     * @return
     */
    public int[] getCurrentQaudrant(AID aid) {
    	return this._currentQuadrant.get(aid);
    }
    
    /**
     * gibt die Länglichkeit der konvexen Hülle zurück.
     * @return
     */
    public double getCurrentConvexHullExzentrität() {
    	return this._polygonExzentrität;
    }
    
    /**
     * gibt zurück ob man im Sichtfeld eines Spielers ist.
     * @param aid
     * @return
     */
    public boolean isInVision(AID aid) {
    	return this._currentInVision.get(aid);
    }
    
    /**
     * gibt zurück ob man sich in der konvexen Hülle befindet.
     * @return
     */
    public boolean isInConvexHull() {
    	return this._insideConvexHull;
    }
  
    /**
     * startet alle Berechnungen.
     */
	private void execute() {
		//Quadranten aller Spieler bestimmen.
		this.captureQuadrant();
		
		//Bestimmten ob man vom Spieler gesehen wird.
		this.captureVision();
		
		//Bestimmt die konvexe Hülle, Schwerpunkt, etc.
		if(Brain.getEnemyAIDs().size() >= 3) {
			this.captureConvexHullStuff();
		}
	}

	/**
	 * gibt die Anzahl der Feinde in den Quadranten zurück. (variable einstellbares Grid) Bsp: q[0][1] == 3 (3 Feinde im Quadrant 0,1).
	 * @param divideX
	 * @param divideY
	 * @return
	 */
	public int[][] getQaudrantEnemyCount(int divideX, int divideY) {
		int[][] enmeyCount = new int[divideY][divideX];
		
		List<AID> enemies = Brain.getEnemyAIDs();
		for(int i = 0; i < enemies.size(); i++) {
			AID aid = enemies.get(i);
			Move lastMove = Brain.HISTORYCAPTURER.getLastPlayerMove(aid);
			if(lastMove != null) {
				int[] quadrant = this.getQuadrant(lastMove.getNode(), divideX, divideY);
				enmeyCount[quadrant[0]][quadrant[1]]++;
			}
		}
		return enmeyCount;
	}
	
	/**
	 * gibt die Anzahl der Feinde in den Quadranten zurück. (fixe Grid Größe) Bsp: q[0][1] == 3 (3 Feinde im Quadrant 0,1).
	 * @return
	 */
	public int[][] getQaudrantEnemyCount() {
		return this.getQaudrantEnemyCount(2, 2);
	}
	
	
	
	
}
